﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.FxCop.Sdk;
namespace Community.StaticAnalysis.Rules.Tests
{
    /// <summary>
    /// a class that helps me retrieve methodNodes form this assembly
    /// </summary>
    internal static class CcUtil
    {

        #region Methods

        public static Method GetMethod(Type containingType, string methodName)
        {
            return GetMethod(containingType, methodName, new TypeNode[] { });
        }

        public static PropertyNode GetProperty(Type containingType, string propertyName) 
        {
            TypeNode type = GetTypeNode(containingType);
            PropertyNode prop  = type.GetProperty(Identifier.For(propertyName));
            
            return prop;
        }


        public static TypeNode GetTypeNode(Type type) 
        {
            AssemblyNode assemblyNode = AssemblyNode.GetAssembly(type.Assembly.Location);

            Identifier namespaceIdentifier = Identifier.For(type.Namespace);
            Identifier typeIdentifier = Identifier.For(type.Name);

            TypeNode typeNode = assemblyNode.GetType(namespaceIdentifier, typeIdentifier);

            if (typeNode == null)
            {
                throw new InvalidOperationException(string.Format("Could not find {0}", type.FullName));
            }
            return typeNode;            
        }

        //HACK: try to make the GetMethod(type,string, TypeNodes[]) instead of using this method
        public static Method GetFirstMethodMathingMethod(Type containingType, string methodName) 
        {
            TypeNode type = GetTypeNode(containingType);

            MemberCollection collection = type.GetMembersNamed(Identifier.For(methodName));

            foreach (Member m in collection) {
                Method method = m as Method;
                if (method != null) {
                    return method;
                }
            }

            throw new InvalidOperationException(string.Format("Could not find {0} in type {1}", methodName, containingType.FullName));            

        }


        public static Method GetMethod(Type containingType, string methodName, params TypeNode[] paramTypes)
        {

            TypeNode typeNode = GetTypeNode(containingType);

            Identifier methodIdentifier = Identifier.For(methodName);


            if (typeNode == null)
            {
                throw new InvalidOperationException(string.Format("Could not find {0}", containingType.FullName));
            }

            Method method = typeNode.GetMethod(methodIdentifier, GetReferenceTypeNodes(paramTypes));

            if (method == null) {
                throw new InvalidOperationException(string.Format("Could not find {0} in type {1}",methodName, containingType.FullName));
            }

            return method;
        }

        private static TypeNode[] GetReferenceTypeNodes(TypeNode[] types)
        {
            List<TypeNode> list = new List<TypeNode>();

            if (types == null) { return new TypeNode[] { }; }

            foreach (TypeNode type in types)
            {
                list.Add(type.GetReferenceType());
            }

            return list.ToArray();
        }


        #endregion


    }



}
